package com.gaodun.ts.controller;

import com.gaodun.ts.oom.JavaVMStackSOF;
import com.gaodun.ts.oom.OOMObject;
import com.zhengcheng.common.web.Result;
import com.zhengcheng.web.support.BaseController;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * OOMController
 *
 * @author :    zhangquansheng
 * @date :    2019/12/12 17:18
 */
@Slf4j
@RestController
@RequestMapping
public class OOMController extends BaseController {

    @ApiOperation(value = "堆溢出")
    @GetMapping("/heapOOM")
    public Result<Void> heapOOM() {
        List<OOMObject> list = new ArrayList<>();
        while (true) {
            list.add(new OOMObject());
        }
    }

    @ApiOperation(value = "SOF异常")
    @GetMapping("/sof")
    public Result<Void> sof() {
        JavaVMStackSOF oom = new JavaVMStackSOF();
        oom.stackLeak();
        return Result.success();
    }

    @ApiOperation(value = "元空间溢出")
    @GetMapping("/metaspace")
    public Result<Void> metaspace() {
        // String.intern()方法是一种手动将字符串加入常量池中的方法，原理如下：如果在常量池中存在与调用intern()方法的字符串等值的字符串，就直接返回常量池中相应字符串的引用，否则在常量池中复制一份该字符串，并将其引用返回（Jdk7中会直接在常量池中保存当前字符串的引用）；
        // String.intern()方法主要适用于程序中需要保存有限个会被反复使用的值的场景，这样可以减少内存消耗，同时在进行比较操作时减少时耗，提高程序性能。
        String str1 = new StringBuilder("计算机").append("软件").toString();
        System.out.println(str1.intern() == str1);
        String str2 = new StringBuilder("ja").append("va").toString();
        System.out.println(str2.intern() == str2);

        while (true) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(OOMObject.class);
            enhancer.setUseCache(false);
            enhancer.setCallback(new MethodInterceptor() {
                @Override
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    return methodProxy.invokeSuper(o, objects);
                }
            });
            enhancer.create();
        }


//        List<String> list = new ArrayList<>();
//        int i = 0;
//        while (true) {
//            list.add(String.valueOf(i++).intern());
//        }
    }

    @ApiOperation(value = "本机直接内存溢出")
    @GetMapping("/directMemory")
    public Result<Void> directMemory() throws IllegalAccessException {
        Field unsafeField = Unsafe.class.getDeclaredFields()[0];
        unsafeField.setAccessible(true);
        Unsafe unsafe = (Unsafe) unsafeField.get(null);
        while (true) {
            // 1M
            unsafe.allocateMemory(1024 * 1024);
        }
    }

}
